package com.idlecode.util;

import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @program: IdleCode
 * @description
 * @author: rongjuwei
 * @create: 2024-10-25 13:25
 **/
public class UUIDUtil {

    /**
     * 批量生成UUID (支持指定生成的UUID版本，并指定是否包含连字符)
     *
     * @param version        版本
     *                       1：生成基于时间的 UUID（UUID v1）。
     *                       3：生成基于 MD5 哈希的 UUID（UUID v3），需要提供 namespace 和 name 参数。
     *                       4：生成随机的 UUID（UUID v4）。
     *                       5：生成基于 SHA-1 哈希的 UUID（UUID v5），需要提供 namespace 和 name 参数。
     * @param count          指定生成的 UUID 数量。传入一个整数，表示要生成多少个 UUID。例如，传入 5 表示生成 5 个 UUID。
     * @param namespace      命名空间字符串，只有在生成 v3 或 v5 UUID 时需要。命名空间用于生成基于哈希的 UUID（v3 和 v5）时的唯一性。
     *                       一般为一个有效的 UUID 字符串形式（如 550e8400-e29b-41d4-a716-446655440000）
     * @param name           命名空间内的名称，只有在生成 v3 或 v5 UUID 时需要。name 和 namespace 一起用于计算 UUID 的哈希值，
     *                       以确保在同一个命名空间内相同名称生成的 UUID 是一致的。
     * @param includeHyphens 布尔值，用于指定生成的 UUID 字符串是否包含连字符 -
     *                       true：生成的 UUID 字符串包含连字符（如 550e8400-e29b-41d4-a716-446655440000）。
     *                       false：生成的 UUID 字符串不包含连字符（如 550e8400e29b41d4a716446655440000）。
     * @return
     */
    public static List<String> generateUUIDs(int version, int count, String namespace, String name, boolean includeHyphens) {
        List<String> uuids = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            UUID uuid;
            switch (version) {
                case 1:
                    uuid = generateV1UUID();
                    break;
                case 3:
                    uuid = generateV3UUID(namespace, name);
                    break;
                case 4:
                    uuid = generateV4UUID();
                    break;
                case 5:
                    uuid = generateV5UUID(namespace, name);
                    break;
                default:
                    throw new IllegalArgumentException("Invalid UUID version specified");
            }
            uuids.add(formatUUID(uuid, includeHyphens));
        }
        return uuids;
    }

    // 生成v1版本UUID (基于时间和MAC地址)
    public static UUID generateV1UUID() {
        try {
            long time = System.currentTimeMillis();
            InetAddress addr = InetAddress.getLocalHost();
            byte[] mac = addr.getAddress();

            long mostSigBits = (time & 0xFFFFFFFFFFFFL) << 16;
            mostSigBits |= 0x1000; // version 1
            long leastSigBits = (long) (Math.random() * Long.MAX_VALUE);
            leastSigBits &= 0x3FFFFFFFFFFFFFFFL;
            leastSigBits |= 0x8000000000000000L; // variant
            return new UUID(mostSigBits, leastSigBits);
        } catch (Exception e) {
            throw new RuntimeException("Error generating v1 UUID", e);
        }
    }

    // 生成v3版本UUID (基于MD5哈希)
    public static UUID generateV3UUID(String namespace, String name) {
        try {
            UUID namespaceUUID = UUID.fromString(namespace);
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(toBytes(namespaceUUID));
            md.update(name.getBytes());
            byte[] hash = md.digest();
            return constructUUID(hash, 3);
        } catch (Exception e) {
            throw new RuntimeException("Error generating v3 UUID", e);
        }
    }

    // 生成v4版本UUID (随机UUID)
    public static UUID generateV4UUID() {
        return UUID.randomUUID();
    }

    // 生成v5版本UUID (基于SHA-1哈希)
    public static UUID generateV5UUID(String namespace, String name) {
        try {
            UUID namespaceUUID = UUID.fromString(namespace);
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            sha1.update(toBytes(namespaceUUID));
            sha1.update(name.getBytes());
            byte[] hash = sha1.digest();
            return constructUUID(hash, 5);
        } catch (Exception e) {
            throw new RuntimeException("Error generating v5 UUID", e);
        }
    }

    // 将UUID转换为byte数组
    private static byte[] toBytes(UUID uuid) {
        ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
        byteBuffer.putLong(uuid.getMostSignificantBits());
        byteBuffer.putLong(uuid.getLeastSignificantBits());
        return byteBuffer.array();
    }

    // 根据哈希值构建UUID
    private static UUID constructUUID(byte[] hash, int version) {
        long mostSigBits = 0;
        long leastSigBits = 0;
        for (int i = 0; i < 8; i++) {
            mostSigBits = (mostSigBits << 8) | (hash[i] & 0xff);
        }
        for (int i = 8; i < 16; i++) {
            leastSigBits = (leastSigBits << 8) | (hash[i] & 0xff);
        }
        mostSigBits &= ~(0xF000L); // clear version
        mostSigBits |= ((long) version << 12); // set version
        leastSigBits &= ~(0xC000000000000000L); // clear variant
        leastSigBits |= 0x8000000000000000L; // set to IETF variant
        return new UUID(mostSigBits, leastSigBits);
    }

    // 格式化UUID，根据是否需要连字符返回UUID字符串
    private static String formatUUID(UUID uuid, boolean includeHyphens) {
        return includeHyphens ? uuid.toString() : uuid.toString().replace("-", "");
    }

    public static void main(String[] args) {
        // 示例：生成5个v4版本的UUID，不包含连字符
        List<String> uuids = generateUUIDs(4, 5, null, null, false);
        uuids.forEach(System.out::println);
    }
}
